# 继承父类样例
# 父类/超类/基类
"""
class Parent1:
    xxx = 333
    def run(self):
        print("我是父类")
# 派生类/子类
class Sub1(Parent1):
    pass

obj = Sub1()
obj.run() # 执行的父类方法
# 执行方法的顺序： 子类优先选择——>父类
print(obj.xxx)
"""
'''
总结对象的相似之处得到了类
总结类的相似之处得到父类
'''
"""
class People(object): # 虽然没有写继承类，但是默认都是继承的object
    school = "不知道"
    def __init__(self,name,age,sex):
        self.sex = sex
        self.name = name
        self.age = age
class Student(People): # 学生类，继承人类
    # def __init__(self,name,age,sex):
    #     self.name = name
    #     self.age = age
    #     self.sex = sex

    def play(self):
        print("%s play football" % self.name)
class Teacher(People):
    def course(self):
        print('%s course' % self.name)
# 实例化的时候子类没有__init__方法会调用父类的
stu1 = Student("王长帅",49,"女")
print(stu1.__dict__)
# {'sex': '女', 'name': '王长帅', 'age': 49}
tea1 = Teacher("小白",18,"男")
print(tea1.__dict__)
# {'sex': '男', 'name': '小白', 'age': 18}

"""

# 子类派生的新方法中重用父类功能
'''
子类重用父类的功能
在子类派生出的新方法中重用父类功能的方式一:
指名道姓地引用某一个类中的函数 （与继承无关）
'''
"""
class People:
    school = "不知道啊"
    def __init__(self,name,age,sex):
        self.name = name
        self.age = age
        self.sex = sex
class Student():
    def __init__(self,name,age,sex,score = 0):
        People.__init__(self,name,age,sex) # 重用了people实例属性
        self.score = score
    def play(self):
        print("%s play football" % self.name)

stu1 = Student("王长帅",59,"女")
print(stu1.__dict__)
# {'name': '王长帅', 'age': 59, 'sex': '女', 'score': 0}
"""
# 在子类派生的新方法中重用父类功能的方式二
"""
'''
派生实例化除了父类的属性添加，还能有自己独有的属性 ******
在子类派生出的新方法中重用父类功能的方式二:super()必须在类中用
super(自己的类名,自己的对象)
可以省略传值
super()
'''

class People:
    school = "不知道啊"
    def __init__(self,name,age,sex):
        self.name = name
        self.age = age
        self.sex = sex
class Student(People): # 继承父类
    def __init__(self,name,age,sex,score = 0):
        super(Student,self).__init__(name,age,sex)
        self.score = score # 子类独有的
    def play(self):
        print("%s play football"% self.name)

stu1 = Student("王长帅",99,"女生")
print(stu1.__dict__)
# {'name': '王长帅', 'age': 99, 'sex': '女生', 'score': 0}
"""
# 在单继承背景下的属性查找
# 在单继承背景下属性的查找优先级: 对象->对象的类->父类->父类.....->object
"""
class Foo():
    xxx = 444
    pass
class Bar1(Foo):
    xxx = 333
    pass
class Bar2(Bar1):
    xxx = 222
    pass
obj = Bar2()
print(obj.xxx) # 222
# 对象->对象的类->父类->父类.....->object
"""
"""
class Foo:
    def f1(self):
        print("FOO.f1")
    def f2(self):
        print('Foo.f2')
        self.f1()
class Bar(Foo):
    def f1(self):
        print('Bar.f1')
obj = Bar()
obj.f2()  # Foo.f2
"""

# 在多继承背景下的属性查找
# 在多继承背景下属性的查找优先级: **
# 此时属性的查找优先级是:对象->对象的类->按照从左往右的顺序一个分支一个分支的找下去
# 广度优先查找,从左往右一个分支一个分支的查找,在最后一个分支才去查找顶级类
# 第四层 # 顶级类是在最后一个分之才走的
"""
class G():
    # x = 'G'
    pass
class E(G):
    # x = 'E'
    pass
class F(G):
    #x='F'
    pass
# 第二层
class B(E):
    # x= "B"
    pass
class C(F):
    #x='C'
    pass
class D(G):
    x='D'
    pass
# 第一层
class A(B,C,D): # A继承了B、C、D三个父类
    #x = 'A'
    pass
obj = A()
print(obj.x)
# # python专门为继承类内置了一个mro的方法,用来查看c3算法的计算结
print(A.mro())
"""
"""
class A:
    def eat(self):
        print("吃的汉堡")
class B(A):
    # def eat(self):
    #     print("吃的火锅")
    pass
class C():
    # def eat(self):
    #     print("吃的盒饭")
    pass
class D(C,B): # C算是第一父类，B算是第二父类
    pass
    # def eat(self):
    #     print("吃的水果")

# xs = D()
# xs.eat()
"""
"""
# 先继承子类，再继承它的父类
class E(A,B):
    pass
a = E()
print(a) 
"""
# TypeError: Cannot create a consistent method resolution
# order (MRO) for bases A, B
# 组合
# 组合指的是某一个对象拥有一个属性,该属性的值是另外一个类的对象
"""
class Foo:
    xxx = 100
class Bar:
    yyy = 2000
    def zzz(self):
        print("我是bar方法")
obj = Foo()
obj1 = Bar()

obj.attr = obj1
print(obj.attr) # <__main__.Bar object at 0x00F35390>
print(obj1) # <__main__.Bar object at 0x01AB5370>
print(obj1.yyy) #　２０００　

print(obj.attr.yyy) # 2000
obj1.zzz()
obj.attr.zzz()
# 为何要用组合
# 通过为某一个对象添加属性(属性的值是另外一个类的对象)的方式,可
# 以间接地将两个类关联/整合/组合到一起
# 从而减少类与类之间代码冗余
"""
# 案例
"""
class People:
    school = '不造啊'
    def __init__(self,name,age,sex):
        self.name = name
        self.age = age
        self.sex = sex
class Student(People):
    def __init__(self, name, age, sex,score=0):
        super().__init__(name, age, sex)
        self.score = score
class Teacher(People):
    def __init__(self,name,age,sex,course = []):
        super().__init__(name, age, sex)
        self.course = course # 0x666 =! []
    def tell_info1(self):
        # 这个时候是列表里面装了4个课程对象
        # print(self.course)
        for i in self.course:
            # print(i)
            # 课程属性
            # print('<课程名:%s,价格%s>' % (i.c_name, i.c_price))
            # 课程方法
            i.tell_info()
class Course:
    def __init__(self,c_name,c_price):
        self.c_name = c_name
        self.c_price = c_price
    def tell_info(self):
        print('| 课程名:%s,价格%s |'%(self.c_name,self.c_price))

python = Course('python开发',10000)
math = Course('高等数学',3000)
English = Course('英语',4000)
music = Course('音乐',5000)
drawing = Course('绘画',6000)
dahai = Teacher('龙仔',24,'man')
# dahai.course = music # 这个我没注释，因为这里村的是一个地址值，而不再是列表了   ，一开始默认是一个空的列表
# dahai.course.tell_info() # | 课程名:高等数学,价格3000 |
# 如果我想把一堆的对象放到一个对象属性里面，我们怎么做？
# 思考一下？ 放到一个容器里面 列表

dahai.course.append(python)
dahai.course.append(math)
dahai.course.extend([English,music])
print(dahai.course)
dahai.tell_info1()
"""
# 组合和继承的区别
'''
组合和继承的区别，继承是把全部的属性和方法让子类可以调用，
而组合只是部分的属性和方法把2个类关联到一起，有些类的属性
不能全部继承，这就用到了组合,组合的是对象，而继承的是类，
继承是在类定义产生的，它是类之间的关联关系，
而组合是类定义后产生的关系，因为它是对象的关联关系
'''






























